package com.nineclock.auth.aop;

import com.nineclock.auth.entity.IntegrationAuthenticationEntity;
import com.nineclock.auth.entity.NcOauthTokenDTO;
import com.nineclock.auth.threadlocal.IntegrationAuthenticationHolder;
import com.nineclock.auth.threadlocal.UserHolder;
import com.nineclock.common.entity.Result;
import com.nineclock.common.entity.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 *
 * 切面 = 切入点 + 增强（通知）
 * @author 黑马程序员
 * @Company http://www.ithiema.com
 * @Version 1.0
 */
@Aspect
@Component
@Slf4j
public class AuthTokenAspect {

    @Autowired
    HttpServletRequest request;

    //前置，后置，环绕，最终 四种增强类型中，都可以添加参数 JointPoint(连接点（拦截到的方法）)
    //ProceedingJoinPoint  可以调用原始方法（连接点对应的方法）
    //环绕增强 * com.nineclock.service..*.*(..)
    //环绕增强中一定要调用原始方法
    @Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {


        try {
            //前置增强
            //从请求对象中获取 请求参数
            String authType = request.getParameter("auth_type");
            Map<String, String[]> parameterMap = request.getParameterMap();
            //封装成IntegrationAuthenticationEntity 对象
            IntegrationAuthenticationEntity entity = new IntegrationAuthenticationEntity();
            entity.setAuthType(authType);
            entity.setAuthParameters(parameterMap);

            //存储到当前线程
            IntegrationAuthenticationHolder.set(entity);

            //调用原始方法, 返回值为 原始方法的返回值
            Object resultObj = joinPoint.proceed();

            Result result = null;
            //后置增强(改变返回值)
            ResponseEntity<OAuth2AccessToken> responseEntity = (ResponseEntity<OAuth2AccessToken>) resultObj;
            //如果认证是成功的(封装成功的结果)
            if(responseEntity.getStatusCode().is2xxSuccessful()){
                //从当前线程获取userInfo
                UserInfo userInfo = UserHolder.get();
                //获取认证 的结果对象
                OAuth2AccessToken body = responseEntity.getBody();


                NcOauthTokenDTO ncOauthTokenDTO = new NcOauthTokenDTO();
                ncOauthTokenDTO.setUser(userInfo);
                ncOauthTokenDTO.setOauth2AccessToken(body);

                result = Result.success(ncOauthTokenDTO);

            } else {
                result = Result.errorCodeMessage(401, "获取token失败");
            }

            return ResponseEntity.ok(result);
        } finally {
            //最终增强
            IntegrationAuthenticationHolder.remove();
            UserHolder.remove();

        }
    }

}
